<html>
<head>
    <style>
        * {
            font-family: 'Consolas', 'Ubuntu Mono', 'Monaco', 'Courier New', Courier, sans-serif;
        }
        body {
            margin: 0;
            padding: 0;
        }
        #chat-container {
            padding: 10px;
            width: 33%;
        }
        #debug-container {
            width: 66%;
            overflow-x: hidden;
            background: #eaeaea;
            font-size: 0.7rem;
            padding: 10px;
            margin: 0;
        }
        #debug-state,
        #debug-txs,
        #debug-network {
            min-height: 100vh;
        }
        .hidden {
            display: none;
        }
        #messages .message {
            padding: 10px;
            border-radius: 5px;
            margin: 10px;
        }
        #messages .message img {
            max-width: 80px;
        }
        #form {
            display: flex;
            padding: 10px;
        }
        #form #form-inputs {
            flex-grow: 1;
        }
        #form #input-text {
            width: 100%;
            margin-bottom: 4px;
        }
        #form button {
            background-color: #6200ff;
            border: none;
            border-radius: 3px;
            color: white;
            cursor: pointer;
            margin-left: 4px;
        }
    </style>
</head>
<body>
    <div style='display: flex'>
        <div id='chat-container'>
            <h1>chat</h1>

            <div id='my-address'></div>
            <br/>
            <div>
                Set your username:<br/>
                <input id='input-username'/>&nbsp;
                <button id='btn-set-username'>Set</button>
                <br/>
            </div>
            <br/>
            <br/>

            <div id='messages'></div>
            <div id='form'>
                <div id='form-inputs'>
                    <input id='input-text' />
                    Attachment: <input type='file' id='input-file' />
                </div>
                <button id='btn-send'>Send</button>
            </div>
        </div>
        <div id='debug-container'>
            <button id='btn-view-debug-state' disabled>State</button>
            <button id='btn-view-debug-txs'>Transactions</button>
            <button id='btn-view-debug-network'>Network</button>
            <div id='tab-state'>
                <code>
                    <pre id='debug-state'>
                    </pre>
                </code>
            </div>
            <div id='tab-txs' class='hidden'>
                <code>
                    <pre id='debug-txs'>
                    </pre>
                </code>
            </div>
            <div id='tab-network' class='hidden'>
                <code>
                    <pre id='debug-network'>
                    </pre>
                </code>
            </div>
        </div>
    </div>
</body>

<script src="https://unpkg.com/peerjs@1.0.0/dist/peerjs.min.js"></script>
<script src='/redwood.js'></script>
<script>
    //
    // Identity stuff
    //
    var identity = Redwood.identity.random()
    function refreshIdentityUI() {
        document.getElementById('my-address').innerHTML = '<strong>Your address:</strong> ' + identity.address
    }
    refreshIdentityUI()

    //
    // Redwood/sync9 setup
    //
    var s9 = Redwood.sync9.create()

    var queue = Redwood.utils.createTxQueue(
        (from, vid, parents, patches) => Redwood.sync9.resolve_state(s9, from, vid, parents, patches),
        ({ tx, leaves, state }) => {
            if (!tx) {
                return
            }

            // Update the debug state UI
            currentState = state
            if (!knownTxs[tx.id]) {
                txs.push(tx)
                knownTxs[tx.id] = true
            }
            refreshDebugUI()

            // Update the chat UI
            if (state && state.messages) {
                messages = state.messages.value
            }
            refreshChatUI()
        }
    )

    var braidClient = Redwood.createPeer({
        identity: identity,
        webrtc: true,
        onFoundPeersCallback: (peers) => {
            knownPeers = peers
            refreshDebugUI()
        }
    })

    braidClient.authorize().then(() => {
        braidClient.subscribe({
            stateURI: 'chat.com/room-2837',
            keypath: '/',
            txs: true,
            fromTxID: Redwood.utils.genesisTxID,
            callback: queue.defaultTxHandler,
        })
    })


    //
    // Chat UI
    //
    var messagesElem = document.getElementById('messages')
    var messages = []
    async function refreshChatUI() {
        var allRefsAvailable = true
        var html = ''
        for (var i = 0; i < messages.length; i++) {
            var msg = messages[i]
            var refAvailable
            if (msg.attachment) {
                refAvailable = await available('/messages[' + i + ']/attachment?state_uri=chat.com/room-2837')
                allRefsAvailable = allRefsAvailable && refAvailable
            }
            var sender = currentState && currentState.users && currentState.users[msg.sender]
                ? currentState.users[msg.sender.toLowerCase()].name
                : msg.sender.substr(0, 6)
            html += '<div class="message" style="background-color: ' + strToColor(msg.sender) + '">'
            html += '    <div><b>' + (sender || '') + ':</b> </div>'
            html += '    <div>'
            html += '        <div>' + msg.text + '</div>'
            if (msg.attachment) {
            if (refAvailable) {
            html += '        <img src="/messages[' + i + ']/attachment?state_uri=chat.com/room-2837" />'
            } else {
            refsStillLoading = true
            html += '        <div>(loading...)</div>'
            }
            }
            html += '    </div>'
            html += '</div>'
        }
        messagesElem.innerHTML = html

        if (!allRefsAvailable) {
            setTimeout(refreshChatUI, 1000)
        }

    }

    //
    // Debug UI
    //
    var txs = []
    var knownTxs = {}
    var currentState = {}
    var knownPeers = {}
    var currentDebugTab = 'state'
    var debugTabButtonState = document.getElementById('btn-view-debug-state')
    var debugTabButtonTxs = document.getElementById('btn-view-debug-txs')
    var debugTabButtonNetwork = document.getElementById('btn-view-debug-network')
    var debugStateElem = document.getElementById('debug-state')
    var debugTxsElem = document.getElementById('debug-txs')
    var debugNetworkElem = document.getElementById('debug-network')
    var debugStateTab = document.getElementById('tab-state')
    var debugTxsTab = document.getElementById('tab-txs')
    var debugNetworkTab = document.getElementById('tab-network')
    function refreshDebugUI() {
        debugStateElem.innerHTML = JSON.stringify(currentState, null, 4)
             .replace(/\\\\n/g, '\\n')
             .replace(/</g, '&lt;')
             .replace(/>/g, '&gt;')
        debugTxsElem.innerHTML = JSON.stringify(txs, null, 4)
             .replace(/\\\\n/g, '\\n')
             .replace(/</g, '&lt;')
             .replace(/>/g, '&gt;')
        debugNetworkElem.innerHTML = JSON.stringify(knownPeers, null, 4)
             .replace(/\\\\n/g, '\\n')
             .replace(/</g, '&lt;')
             .replace(/>/g, '&gt;')

        if (currentDebugTab === 'state') {
            debugStateTab.classList.remove('hidden')
            debugTxsTab.classList.add('hidden')
            debugNetworkTab.classList.add('hidden')
            debugTabButtonState.disabled = true
            debugTabButtonTxs.disabled = false
            debugTabButtonNetwork.disabled = false
        } else if (currentDebugTab === 'txs') {
            debugStateTab.classList.add('hidden')
            debugTxsTab.classList.remove('hidden')
            debugNetworkTab.classList.add('hidden')
            debugTabButtonState.disabled = false
            debugTabButtonTxs.disabled = true
            debugTabButtonNetwork.disabled = false
        } else if (currentDebugTab === 'network') {
            debugStateTab.classList.add('hidden')
            debugTxsTab.classList.add('hidden')
            debugNetworkTab.classList.remove('hidden')
            debugTabButtonState.disabled = false
            debugTabButtonTxs.disabled = false
            debugTabButtonNetwork.disabled = true
        }
    }
    debugTabButtonState.addEventListener('click', () => {
        currentDebugTab = 'state'
        refreshDebugUI()
    })
    debugTabButtonTxs.addEventListener('click', () => {
        currentDebugTab = 'txs'
        refreshDebugUI()
    })
    debugTabButtonNetwork.addEventListener('click', () => {
        currentDebugTab = 'network'
        refreshDebugUI()
    })


    //
    // Send message UI
    //
    var inputText = document.getElementById('input-text')
    var inputFile = document.getElementById('input-file')
    document.getElementById('btn-send').addEventListener('click', sendMessage)
    document.getElementById('input-text').addEventListener('keydown', function (evt) {
        if (evt.code === 'Enter' && evt.ctrlKey) {
            evt.stopPropagation()
            evt.preventDefault()
            sendMessage()
        }
    })

    async function sendMessage() {
        var attachment = null
        if (inputFile.files.length > 0) {
            var refHashes = await braidClient.storeBlob(inputFile.files[0])
            attachment = {
                'Content-Type': inputFile.files[0].type,
                'value': {
                    'Content-Type': 'link',
                    'value': 'blob:sha3:' + refHashes.sha3,
                },
            }
        }

        var tx = {
            id: Redwood.utils.randomID(),
            parents: Object.keys(s9.leaves),
            stateURI: 'chat.com/room-2837',
            patches: [
                '.messages.value[' + messages.length + ':' + messages.length + '] = ' + JSON.stringify([{
                    attachment: attachment,
                    sender: identity.address.toLowerCase(),
                    text: inputText.value,
                }]),
            ],
        }

        queue.addTx(tx)

        try {
            braidClient.put(tx)
        } catch (err) {
            console.error('error sending to peer ~>', err)
        }

        inputText.value = ''
        inputFile.value = null
    }

    //
    // Set username UI
    //
    var inputUsername = document.getElementById('input-username')
    document.getElementById('btn-set-username').addEventListener('click', setUsername)

    async function setUsername() {
        var tx = {
            id: Redwood.utils.randomID(),
            parents: Object.keys(s9.leaves),
            stateURI: 'chat.com/room-2837',
            patches: [
                '.users.' + identity.address.toLowerCase() + ' = ' + JSON.stringify({
                    name: inputUsername.value,
                }),
            ],
        }

        queue.addTx(tx)

        try {
            braidClient.put(tx)
        } catch (err) {
            console.error('error sending to peer ~>', err)
        }

        inputUsername.value = ''
    }

    //
    // Utils
    //
    async function available(url) {
        try {
            console.log('requesting', url)
            const resp = await fetch(url)
            console.log('available ~>', resp)
            return resp.status == 200
        } catch (err) {
            return false
        }
    }

    function strToColor(str) {
        return colors[getHashCode(str) % colors.length]
    }

    function getHashCode(str) {
        var hash = 0
        if (str.length === 0) { return hash }
        for (var i = 0; i < str.length; i++) {
            hash = str.charCodeAt(i) + ((hash << 5) - hash)
            hash = hash & hash // Convert to 32bit integer
        }
        if (hash < 0) {
            hash *= -1
        }
        return hash
    }

    var colors = [
        '#FF8A80',
        // '#FF5252',
        // '#FF1744',
        // '#D50000',
        // '#FF80AB',
        '#FF4081',
        // '#F50057',
        // '#C51162',
        // '#EA80FC',
        '#E040FB',
        // '#AA00FF',
        '#B388FF',
        '#7C4DFF',
        '#651FFF',
        '#6200EA',
        '#8C9EFF',
        '#536DFE',
        '#3D5AFE',
        '#304FFE',
        '#82B1FF',
        '#448AFF',
        '#2979FF',
        '#2962FF',
        '#80D8FF',
        '#40C4FF',
        '#00B0FF',
        '#0091EA',
        '#26C6DA',
        '#00BCD4',
        '#00ACC1',
        '#0097A7',
        '#00838F',
        '#006064',
        '#4DB6AC',
        '#26A69A',
        '#009688',
        '#00897B',
        '#00796B',
        '#00695C',
        '#004D40',
        '#66BB6A',
        '#4CAF50',
        '#43A047',
        '#388E3C',
        '#2E7D32',
        '#1B5E20',
        '#FDD835',
        '#FBC02D',
        '#F9A825',
        '#F57F17',
        '#FB8C00',
        '#F57C00',
        '#EF6C00',
        '#E65100',
        '#E64A19',
        '#D84315',
        '#BF360C',
        '#607D8B',
        '#546E7A',
        '#455A64',
    ]
</script>
</html>
